import { Request, Response, NextFunction } from 'express';
import { validateRegisterInput } from '../utils/validator';
import HttpException from '../exceptions/HttpException';
import { UNPROCESSABLE_ENTITY, UNAUTHORIZED } from 'http-status-codes';
import { IUserDocument, User } from '../models/user';
import { UserPayload } from '../typings/jwt';
import jwt from 'jsonwebtoken';

const secret = process.env.JWT_SECRET_KEY! || 'zhufeng';


// 在src文件夹下建立controllers的文件夹，
// 里面一个index.ts用于导入导出，一个user.ts用来处理逻辑：

// 再重新改写controllers下面的user.ts，加入这个utils目录的validator.ts校验器：
export const validate = async (req: Request, res: Response, next: NextFunction) => {
    //     这里需要提取authorization字段。客户端发来的请求头会这么带：
    // Authorization:Bearer token
    // 这里需要提取authorization字段。客户端发来的请求头会这么带：
    const authorization = req.headers['authorization'];
    if (authorization) {
        const token = authorization.split(' ')[1];
        console.log(token, 'validate=》验证拿到客户端的token');
        if (token) {
            try {
                const payload: UserPayload = jwt.verify(token, secret) as UserPayload;
                console.log(payload, '验证=》payload是什么》》');
                const user = await User.findById(payload.id);
                console.log(user, '验证=》user是谁？');
                if (user) {
                    delete user.password;
                    res.json({
                        success: true,
                        data: user
                    });
                } else {
                    next(new HttpException(UNAUTHORIZED, `用户不合法无此用户!`));
                }
            } catch (error) {
                next(new HttpException(UNAUTHORIZED, `token不合法!`));
            }

        } else {
            next(new HttpException(UNAUTHORIZED, `token未提供!`));
        }
    } else {
        next(new HttpException(UNAUTHORIZED, `authorization未提供!`));
    }
}


export const register = async (req: Request, res: Response, next: NextFunction) => {
    try {
        let { username, password, confirmPassword, email, addresses } = req.body;
        const { valid, errors } = validateRegisterInput(username, password, confirmPassword, email);
        if (!valid) {
            throw new HttpException(UNPROCESSABLE_ENTITY, `用户提交数据不正确参数验证失败!`, errors);
        }
        let user: IUserDocument = new User({
            username,
            email,
            password,
            addresses
        });
        let oldUser: IUserDocument | null = await User.findOne({ username: user.username });
        if (oldUser) {
            throw new HttpException(UNPROCESSABLE_ENTITY, `用户名重复!`);
        }
        await user.save();
        let token = user.generateToken();
        res.json({
            success: true,
            data: { token }
        });
    } catch (error) {
        next(error);
        //   通过trycatch捕获错误，有错误后，使用next把错误传给错误中间件。不满足schema的也会抛出错误。
        // 下面完成加密功能。
        // 一般在用户传来密码通过验证后就对其进行加密也可以，更好的方式是插入文档前进行：
        // schema有个pre的方法可以完成这个工作，加密使用bcryptjs进行加密。

    }
}

// 这里把登录验证逻辑交给model了，所以需要给model扩展个方法。
// 在model里加入login的方法：
// 下面服务端需要返回一个token。这次需要在document上添加方法。
// 因为每个user都是一个实例，生成不同的token。
export const login = async (req: Request, res: Response, next: NextFunction) => {
    try {
        let { username, password } = req.body;
        let user = await User.login(username, password);
        if (user) {
            let token = user.generateToken();
            console.log(token, 'login=>token')
            res.json({
                success: true,
                data: {
                    token
                }
            });
        } else {
            throw new HttpException(UNAUTHORIZED, `登录失败`);
        }
    } catch (error) {
        console.log(error, 'error')
        next(error);
    }
}




export const uploadAvatar = async (req: Request, res: Response, _next: NextFunction) => {
    let { userId } = req.body;
    let domain = process.env.DOMAIN || `${req.protocol}://${req.headers.host}`;
    let avatar = `${domain}/uploads/${req.file.filename}`;
    await User.updateOne({ _id: userId }, { avatar });
    res.send({ success: true, data: avatar });
}